/*
 * Copyright (C) 2009 Dimitrios C. Michalakos
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 2 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */
package com.cs.util.db.representation;

import com.cs.util.db.Database;
import com.cs.util.db.ioc.IOController;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;

/**
 * XhtmlTable can be used for creating a XHTML Table representation of a resultset.
 * @author dimitris@jmike.gr
 */
public class XhtmlTable {

    private Database db;
    private ResultSet rs;
    private IOController[] ioc;
    private String title = "Another XHTML Table Respresentation";
    private String cssLink = null;
    private List<Anchor> anchors = new ArrayList<Anchor>();
    private List<Action> actions = new ArrayList<Action>();

    /**
     * Construncts a new XHTML table representation of the designated resultset.
     * @param db the database that the resultset derives from.
     * @param rs the resultset upon which the representation will be built.
     * @throws SQLException
     */
    public XhtmlTable(Database db, ResultSet rs) throws SQLException {
        this.db = db;
        this.rs = rs;
        this.ioc = db.getIOControllerArray(rs);
    }

    /**
     * Closes the internal resultset of this representation and clears meta data resources from memory.
     * @throws java.sql.SQLException
     */
    public void close() throws SQLException {
        db = null;
        rs.close();
        ioc = null;
        title = "Another XHTML Table Respresentation";
        cssLink = null;
        actions.clear();
    }

    /**
     * Sets the title of the XHTML document.
     * @param title the title.
     * Title can be used for:
     * Defining a title in the browser toolbar.
     * Providing a title for the page when it is added to favorites.
     * Displaying a title for the page in search-engine results.
     * @return true if title has been set, false if not.
     */
    public boolean setTitle(String title) {
        if (title != null) {
            this.title = title;
            return true;
        } else {
            return false;
        }
    }

    /**
     * Sets the location of a linked stylesheet for the XHTML document.
     * @param url the url of the css file.
     * @return true if stylesheet URL has been set, false if not.
     */
    public boolean setStylesheetURL(String url) {
        this.cssLink = url;
        return true;
    }

    /**
     * Adds a new Action to this Representation.
     * Actions are URI templates containing variables within brackets.
     * A URI template can easily be compiled into a URL for linking one resource with another.
     * @param name the name of the action.
     * @param label the label of the action.
     * @param template the URI template containing variables within brackets, i.e. http://www.google.com/q={variable}
     * @throws SQLException
     */
    public void addAction(String name, String label, String template) throws SQLException {
        actions.add(new Action(db, rs, name, label, template));
    }

    /**
     * Adds a new anchor to create a link to another document.
     * @param name the name of the anchor.
     * @param caption the caption of the anchor.
     * @param url the URL of the document or bookmark that this anchor points to.
     */
    public void addAnchor(String name, String caption, String url) {
        anchors.add(new Anchor(name, caption, url));
    }

    /**
     * Returns this Representation as a String.
     * @return
     * @throws SQLException
     */
    public String display() throws SQLException {
        StringBuilder s = new StringBuilder();
        s.append("<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Strict//EN\" \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd\">");
        s.append("<html xmlns=\"http://www.w3.org/1999/xhtml\">");
        s.append("<head>");
        s.append("<meta http-equiv=\"Content-Type\" content=\"text/html; charset=UTF-8\" />");
        if (cssLink != null) {
            s.append("<link rel=\"stylesheet\" href=\"" + cssLink + "\" type=\"text/css\" />");
        }
        s.append("<title>" + title + "</title>");
        s.append("</head>");
        s.append("<body>");
        for (int i = 0; i < anchors.size(); i++) {//iterate actions
            if (i > 0) {
                s.append(" | ");
            }
            s.append("<a id=\"" + anchors.get(i).getName() + "\" name=\"" + anchors.get(i).getName() + "\" href=\"" + anchors.get(i).getURL() + "\">" + anchors.get(i).getCaption() + "</a>");
        }
        s.append("<table border=\"1\" cellpadding=\"0\" cellspacing=\"0\">");
        /* Table Header */
        s.append("<thead>");
        s.append("<tr>");
        for (int i = 0; i < ioc.length; i++) {//iterate io controllers
            s.append("<th>" + ioc[i].getLabel() + "</th>");
        }
        for (int i = 0; i < actions.size(); i++) {//iterate actions
            s.append("<th>" + actions.get(i).getLabel() + "</th>");
        }
        s.append("</tr>");
        s.append("</thead>");
        /* Table Footer */
        s.append("<tfoot>");
        s.append("<tr>");
        s.append("<td colspan=\"" + String.valueOf(ioc.length + actions.size()) + "\">&nbsp;</td>");
        s.append("</tr>");
        s.append("</tfoot>");
        /* Table Body */
        s.append("<tbody>");
        rs.beforeFirst();
        while (rs.next()) {
            s.append("<tr>");
            for (int i = 0; i < ioc.length; i++) {//iterate io controllers
                String value = ioc[i].getXhtmlTableData(rs);
                if (value == null) {
                    value = "NULL";
                }
                s.append("<td>" + value + "</td>");
            }
            for (int i = 0; i < actions.size(); i++) {//iterate actions
                Action action = actions.get(i);//get current action
                s.append("<td>");
                s.append("<a href=\"" + action.getURL(rs) + "\">" + action.getLabel() + "</a>");
                s.append("</td>");
            }
            s.append("</tr>");
        }
        s.append("</tbody>");
        s.append("</table>");
        s.append("</body>");
        s.append("</html>");
        return s.toString();
    }

    private class Anchor {

        private final String name;
        private final String caption;
        private final String url;

        public Anchor(String name, String caption, String url) {
            this.name = name;
            this.caption = caption;
            this.url = url;
        }

        public String getName() {
            return name;
        }

        public String getCaption() {
            return caption;
        }

        public String getURL() {
            return url;
        }
    }
}
